package com.hybrid.jsbridge;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.text.TextUtils;
import com.hybrid.utils.TaoLog;
import com.hybrid.webview.WVWebView;

/**
 * 插件统一管理
 *
 * @author: zhiwei
 * @date: 2017-10-09 22:27
 * @version: 9.1.0
 */
public class WVPluginManager {
    private static final String TAG = "WVPluginManager";
    private static final Map<String, WVPluginInfo> plugins = new HashMap<String, WVPluginInfo>();
    private static final Map<String, String> aliasPlugins = new HashMap<String, String>();
    private static final String SEPARATOR = "::";
    public static final String KEY_NAME = "name";
    public static final String KEY_METHOD = "method";

    /**
     * @see #registerPlugin(String, Class, boolean)
     */
    public static void registerPlugin(String name, Class<? extends WVApiPlugin> cls) {
        registerPlugin(name, cls, false);
    }

    /**
     * 注册jsbridge插件，方式一（推荐）
     *
     * @param name
     *            对象名，对应js 调用名称
     * @param cls
     *            Class对象
     * @param customLoader
     *            同时注册classloader
     */
    public static void registerPlugin(String name, Class<? extends WVApiPlugin> cls, boolean customLoader) {
        if (!TextUtils.isEmpty(name) && cls != null) {
            ClassLoader loader = null;
            if (customLoader) {
                loader = cls.getClassLoader();
            }
            WVPluginInfo info = new WVPluginInfo(cls.getName(), loader);
            plugins.put(name, info);
        }
    }

    /**
     * 注册jsbridge插件，方式一（推荐）
     *
     * @param name
     *            对象名，对应js 调用名称
     * @param cls
     *            Class对象
     * @param obj
     *            同时注册classloader
     */
    public static void registerPluginwithParam(String name, Class<? extends WVApiPlugin> cls, Object... obj) {
        if (!TextUtils.isEmpty(name) && cls != null) {
            ClassLoader loader = cls.getClassLoader();
            WVPluginInfo info = new WVPluginInfo(cls.getName(), loader);
            if (obj != null) {
                info.setParamObj(obj);
            }
            plugins.put(name, info);
        }
    }

    /**
     * @see #registerPlugin(String, Class)
     */
    @Deprecated
    public static void registerPlugin(String name, String fullClassName) {
        registerPlugin(name, fullClassName, null);
    }

    /**
     * 注册jsbridge插件，方式二
     *
     * @param name
     *            对象名，对应js 调用名称
     * @param fullClassName
     *            类全名
     * @param loader
     *            ClassLoader
     * @see #registerPlugin(String, Class)
     */
    @Deprecated
    public static void registerPlugin(String name, String fullClassName, ClassLoader loader) {
        if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(fullClassName)) {
            WVPluginInfo info = new WVPluginInfo(fullClassName, loader);
            plugins.put(name, info);
        }
    }

    public static void registerPlugin(String name, String fullClassName, ClassLoader loader,Object... obj) {
        if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(fullClassName)) {
            WVPluginInfo info = new WVPluginInfo(fullClassName, loader);
            info.setParamObj(obj);
            plugins.put(name, info);
        }
    }

    /**
     * 注册jsbridge plugin 别名
     *
     * @param aliasName
     *            别名对象名称
     * @param aliasMethod
     *            别名方法名
     * @param originalName
     *            实际对象名
     * @param originalMethod
     *            实际方法名
     */
    public static void registerAlias(String aliasName, String aliasMethod, String originalName, String originalMethod) {
        if (!plugins.containsKey(originalName) || TextUtils.isEmpty(aliasName) || TextUtils.isEmpty(aliasMethod)) {
            TaoLog.w(TAG, "registerAlias quit, this is no original plugin or alias is invalid.");
            return;
        }
        if (!TextUtils.isEmpty(originalName) && !TextUtils.isEmpty(originalMethod)) {
            aliasPlugins.put(aliasName + SEPARATOR + aliasMethod, originalName + SEPARATOR + originalMethod);
        }
    }

    public static Map<String, String> getOriginalPlugin(String aliasName, String aliasMethod) {
        if (TextUtils.isEmpty(aliasName) || TextUtils.isEmpty(aliasMethod)) {
            TaoLog.w(TAG, "getOriginalPlugin failed, alias is empty.");
            return null;
        }
        String original = aliasPlugins.get(aliasName + SEPARATOR + aliasMethod);
        if (!TextUtils.isEmpty(original)) {
            int index = original.indexOf(SEPARATOR);
            if (index > 0) {
                String name = original.substring(0, index);
                String method = original.substring(index + SEPARATOR.length());
                Map<String, String> map = new HashMap<String, String>();
                map.put(KEY_NAME, name);
                map.put(KEY_METHOD, method);
                return map;
            }
        }
        return null;
    }

    public static void unregisterPlugin(String name) {
        plugins.remove(name);
    }

    public static void unregisterAlias(String aliasName, String aliasMethod) {
        if (TextUtils.isEmpty(aliasName) || TextUtils.isEmpty(aliasMethod)) {
            TaoLog.w(TAG, "unregisterAlias quit, alias is invalid.");
            return;
        }
        aliasPlugins.remove(aliasName + SEPARATOR + aliasMethod);
    }

    /**
     * 根据注册的插件创建实体
     */
    public static WVApiPlugin createPlugin(String name, Context context, WVWebView webView) {
        WVPluginInfo pluginInfo = plugins.get(name);
        String className;
        if (pluginInfo == null || TextUtils.isEmpty(className = pluginInfo.getClassName())) {
            if (TaoLog.getLogStatus()) {
                TaoLog.w(TAG, "create plugin failed, plugin not register or empty, " + name);
            }
            return null;
        }
        try {
            ClassLoader loader = pluginInfo.getClassLoader();
            Class<?> clazz;
            if (loader == null) {
                clazz = Class.forName(className);
            } else {
                clazz = loader.loadClass(className);
            }
            if (clazz != null && WVApiPlugin.class.isAssignableFrom(clazz)) {
                WVApiPlugin plugin = (WVApiPlugin) clazz.newInstance();
                if(plugin.paramObj!=null) {
                    plugin.initialize(context, webView, plugin.paramObj);
                } else {
                    plugin.initialize(context, webView);
                }
                return plugin;
            }
        } catch (Exception e) {
            TaoLog.e(TAG, "create plugin error: " + name + ". " + e.getMessage());
        }
        if (TaoLog.getLogStatus()) {
            TaoLog.w(TAG, "create plugin failed: " + name);
        }
        return null;
    }

    static class WVPluginInfo {
        private String className;
        private ClassLoader classLoader;
        private Object paramObj;

        WVPluginInfo(String className) {
            this.className = className;
        }

        WVPluginInfo(String className, ClassLoader classLoader) {
            this.className = className;
            this.classLoader = classLoader;
        }

        public String getClassName() {
            return className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public ClassLoader getClassLoader() {
            return classLoader;
        }

        public void setClassLoader(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }

        public Object getParamObj() {
            return paramObj;
        }

        public void setParamObj(Object paramObj) {
            this.paramObj = paramObj;
        }
    }
}
